package org.lxw.stock;

import java.io.File;
import java.util.Date;
import java.util.SortedMap;

import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.Environment;
import com.sleepycat.je.EnvironmentConfig;
import com.sleepycat.persist.EntityStore;
import com.sleepycat.persist.PrimaryIndex;
import com.sleepycat.persist.StoreConfig;
import com.sleepycat.persist.model.Entity;
import com.sleepycat.persist.model.PrimaryKey;

public class StockDb {
	@Entity
	static public class StockMin5 {
		@PrimaryKey
		long key;
		float open;
		float low;
		float high;
		float close;
		float turnover;
		int volume;

		@SuppressWarnings("unused")
		private StockMin5() {
		}

		public StockMin5(long date, int id) {
			this.key = getKey(date, id);
		}

		public long getDate() {
			return ((int) key) * 60000l;
		}

		public int getStockid() {
			return (int) (key >> 32);
		}

		public void setKey(long key) {
			this.key = key;
		}

		public float getOpen() {
			return open;
		}

		public void setOpen(float open) {
			this.open = open;
		}

		public float getLow() {
			return low;
		}

		public void setLow(float low) {
			this.low = low;
		}

		public float getHigh() {
			return high;
		}

		public void setHigh(float high) {
			this.high = high;
		}

		public float getClose() {
			return close;
		}

		public void setClose(float close) {
			this.close = close;
		}

		public float getTurnover() {
			return turnover;
		}

		public void setTurnover(float turnover) {
			this.turnover = turnover;
		}

		public int getVolume() {
			return volume;
		}

		public void setVolume(int volume) {
			this.volume = volume;
		}

		@Override
		public String toString() {
			return getStockid() + "," + new Date(getDate()).toLocaleString()
					+ "," + getOpen() + "," + getLow() + "," + getHigh() + ","
					+ getClose() + "," + getTurnover() + "," + getVolume();
		}
	}

	@Entity
	static public class StockDay {
		@PrimaryKey
		long key;
		float open;
		float low;
		float high;
		float close;
		float lastclose;
		float turnover;
		int volume;

		@SuppressWarnings("unused")
		private StockDay() {
		}

		public StockDay(long date, int id) {
			key = id;
			key <<= 32;
			key += date / 60000;
		}

		public long getDate() {
			return ((int) key) * 60000l;
		}

		public int getStockid() {
			return (int) (key >> 32);
		}

		public void setKey(long key) {
			this.key = key;
		}

		public float getOpen() {
			return open;
		}

		public void setOpen(float open) {
			this.open = open;
		}

		public float getLow() {
			return low;
		}

		public void setLow(float low) {
			this.low = low;
		}

		public float getHigh() {
			return high;
		}

		public void setHigh(float high) {
			this.high = high;
		}

		public float getClose() {
			return close;
		}

		public void setClose(float close) {
			this.close = close;
		}

		public float getTurnover() {
			return turnover;
		}

		public float getLastClose() {
			return lastclose;
		}

		public void setLastClose(float lastclose) {
			this.lastclose = lastclose;
		}

		public void setTurnover(float turnover) {
			this.turnover = turnover;
		}

		public int getVolume() {
			return volume;
		}

		public void setVolume(int volume) {
			this.volume = volume;
		}

		@Override
		public String toString() {
			return getStockid() + "," + new Date(getDate()).toLocaleString()
					+ "," + getOpen() + "," + getLow() + "," + getHigh() + ","
					+ getClose() + "," + getLastClose() + "," + getTurnover()
					+ "," + getVolume();
		}
	}

	private Environment env;
	final private EntityStore store;
	final private PrimaryIndex<Long, StockMin5> primaryMin5Index;
	final private PrimaryIndex<Long, StockDay> primaryDayIndex;

	public StockDb(File envHome) throws DatabaseException {
		/* Open a transactional Berkeley DB engine environment. */
		EnvironmentConfig envConfig = new EnvironmentConfig();
		envConfig.setAllowCreate(true);
		envConfig.setTransactional(true);
		env = new Environment(envHome, envConfig);

		/* Open a transactional entity store. */
		StoreConfig storeConfig = new StoreConfig();
		storeConfig.setAllowCreate(true);
		storeConfig.setTransactional(false);
		store = new EntityStore(env, "StockStore", storeConfig);
		primaryMin5Index = store.getPrimaryIndex(Long.class, StockMin5.class);
		primaryDayIndex = store.getPrimaryIndex(Long.class, StockDay.class);
	}

	public static long getKey(long date, int id) {
		long key = id;
		key <<= 32;
		key += date / 60000;
		return key;
	}

	public StockMin5 getMin5(long date, int id) {
		return primaryMin5Index.get(getKey(date, id));
	}

	public StockDay getDay(long date, int id) {
		return primaryDayIndex.get(getKey(date, id));
	}

	public boolean put(StockMin5 stock) {
		return primaryMin5Index.putNoOverwrite(stock);
	}

	public boolean put(StockDay stock) {
		return primaryDayIndex.putNoOverwrite(stock);
	}

	public SortedMap<Long, StockMin5> getMin5SortedMap() {
		return primaryMin5Index.sortedMap();
	}

	public SortedMap<Long, StockDay> getDaySortedMap() {
		return primaryDayIndex.sortedMap();
	}

	public void close() throws DatabaseException {
		store.close();
		env.close();
	}
}
